﻿using System;
using System.Collections;
using RAP.Framework.Libary.Utils;
using static RAP.Framework.Libary.DataSource.ServiceUtils;
using System.Threading.Tasks;
using RAP.Framework.Libary.DataSource.DataReader;
using RAP.Framework.Libary.Utils.Factory;
using System.Collections.Specialized;
using RAP.Framework.Libary.DataSource.Model;
using System.Collections.Generic;
using RAP.Framework.Libary.DomTemplateBuilder.Interface;
using RAP.Framework.Libary.DataSource.Context;
using RAP.Framework.Libary.SqlTaskParser;

namespace RAP.Framework.Libary.DataSource
{
  /// <summary>
  /// 数据源读取Helper
  /// </summary>
  public static class DataSourceHelper
  {
    /// <summary>
    /// 发生错误的事件
    /// </summary>
    public static event Action<IDictionary> OnError;


    /// <summary>
    /// 是否允许调试Sql语句
    /// </summary>
    public static bool AllowDebug { get; set; }

    /// <summary>
    /// 调试的事件
    /// </summary>
    public static event Action<string, IQueryParams, IDictionary> OnDebugSql;

    /// <summary>
    /// 即将执行SQL任务
    /// </summary>
    public static event Action<SqlTask, IQueryParams, IDataServiceContext> OnBeforeExecutingSqlTask;

    /// <summary>
    /// 触发错误事件
    /// </summary>
    /// <param name="exp"></param>
    public static void FireErrorEvent( Exception exp )
    {
      FireErrorEvent( exp.ToDictionary() );
    }

    /// <summary>
    /// 触发错误事件
    /// </summary>
    /// <param name="msg"></param>
    public static void FireErrorEvent( string msg )
    {
      FireErrorEvent( new Exception( msg ) );
    }

    /// <summary>
    /// 触发错误事件
    /// </summary>
    /// <param name="error"></param>
    public static void FireErrorEvent( IDictionary error )
    {
      if ( OnError != null )
      {
        Task.Run( ( ) =>
        {
          OnError( error );
        } );
      }
    }

    /// <summary>
    /// 触发调试事件
    /// </summary>
    /// <param name="sql"></param>
    /// <param name="param"></param>
    /// <param name="context"></param>
    public static void FireDebugSqlEvent( string sql, IQueryParams param, IDataServiceContext context )
    {
      if ( OnDebugSql != null )
      {
        Task.Run( ( ) =>
        {
          OnDebugSql( sql, param, context );
        } );
      }
    }

    /// <summary>
    /// 触发即将执行SQL任务的事件
    /// </summary>
    /// <param name="task"></param>
    /// <param name="param"></param>
    /// <param name="context"></param>
    public static void FireBeforeExecutingSqlTask(SqlTask task, IQueryParams param, IDataServiceContext context)
    {
      OnBeforeExecutingSqlTask?.Invoke(task, param, context);
    }

    /// <summary>
    /// 获取数据查询服务工厂对象
    /// </summary>
    public static IFactory<IDataSourceService> DataSourceFactory { get; set; } = new DataSourceFactory();

    /// <summary>
    /// 获取数据解析工厂对象
    /// </summary>
    public static IFactory<IDataReaderParser> DataReaderParsers { get; set; } = new DataParserFactory();

    /// <summary>
    /// 数据实体构造器工厂对象
    /// </summary>
    public static IDataModelGeneratorFactory DataModelGenerator { get; set; } = new DataModelGeneratorFactory();

    /// <summary>
    /// 异步的执行数据查询服务
    /// </summary>
    /// <param name="serviceIdentity"></param>
    /// <param name="param"></param>
    /// <param name="context">上下文对象</param>
    public static async Task<IQueryResult> InvokeDataService
    (
        string serviceIdentity = SERVICE_SQL_IDENTITY
        , IQueryParams param = null
        , IDataServiceContext context = null
    )
    {
      var service = DataSourceFactory[ serviceIdentity ];
      var result = new QueryResult();
      if ( service != null )
      {
        await service.InvokeService( param, result, context );
      }
      else
      {
        result.Error = ServiceError.InvalidDataSource.FormatMessage( serviceIdentity );
      }
      return result;
    }

    /// <summary>
    /// 同步执行数据查询服务
    /// </summary>
    /// <param name="serviceIdentity"></param>
    /// <param name="param"></param>
    /// <param name="context"></param>
    /// <returns></returns>
    public static QueryResult InvokeDataServiceSync
    (
        string serviceIdentity = SERVICE_SQL_IDENTITY
        , IQueryParams param = null
        , IDataServiceContext context = null
    )
    {
      var service = DataSourceFactory[ serviceIdentity ];
      var result = new QueryResult();
      if ( service != null )
      {
        service.InvokeServiceSync( param, result, context );
      }
      else
      {
        result.Error = ServiceError.InvalidDataSource.FormatMessage( serviceIdentity );
      }
      return result;
    }
  }
}